package com.sigmazero13.MKDummy.activites;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;
import java.util.Set;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.TextView.BufferType;
import android.widget.Toast;

import com.sigmazero13.MKDummy.R;
import com.sigmazero13.MKDummy.components.CardDisplayView;
import com.sigmazero13.MKDummy.components.CrystalDisplayView;
import com.sigmazero13.MKDummy.listeners.OnTabUnselectedListener;
import com.sigmazero13.MKDummy.listeners.PlayerListener;
import com.sigmazero13.MKDummy.models.CardDeck;
import com.sigmazero13.MKDummy.models.DummyPlayer;
import com.sigmazero13.MKDummy.models.MKCharacter;
import com.sigmazero13.MKDummy.models.ManaColor;
import com.sigmazero13.MKDummy.models.VolkarePlayer;
import com.sigmazero13.MKDummy.utils.CardDisplayViewFactory;
import com.sigmazero13.MKDummy.utils.CrystalDisplayViewFactory;
import com.sigmazero13.MKDummy.utils.StringUtils;

public class MKDummyPlayer extends Fragment implements OnClickListener, PlayerListener, OnDismissListener, OnTabUnselectedListener {
	public static final String CHARACTER_NAME = "character_name";
	public static final String DUMMY_PLAYER_KEY = "dummy_player";
	public static final String RESTORE_GAME = "restore";
	public static final String GAME_LOG = "game_log";
	public static final String NUM_WOUNDS = "num_wounds";
	public static final String TACTICS_ONLY = "tactics_only";
	
	public static final int NEW_ROUND_DIALOG = 200;
	
	private DummyPlayer player;
	
	private CardDisplayView cardDisplay;
	private CrystalDisplayView crystalDisplay;
	
	private TextView roundStatus;
	private TextView playerLog;
	private ScrollView playerLogScroll;
	
	private Button playTurnButton;
	private Button endRoundButton;
	
	private Boolean saveStateOnDestroy = true;
	private Boolean showWounds = false;
	private Boolean endOfRound = false;
	
	private View mainView = null;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		Bundle bundle = getActivity().getIntent().getExtras();
		String characterName = bundle.getString(CHARACTER_NAME);
		MKCharacter character = MKCharacter.findByName(characterName);
		
		if (bundle.getBoolean(RESTORE_GAME, false)) {
			restoreGameFromFile();
		} else {
			if (character.getName().equals(MKCharacter.VOLKARE.getName())) {
				Integer numWounds = bundle.getInt(NUM_WOUNDS, 14);
				player = new VolkarePlayer(numWounds);
			} else {
				player = new DummyPlayer(character.getName(), character.getDefaultCrystals());
			}
			
			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
		    if (prefs.getBoolean("enable_tactics", false)) {
		    	Bundle b = new Bundle();
		    	b.putBoolean(TACTICS_ONLY, true);
		    	getActivity().showDialog(NEW_ROUND_DIALOG, b);
		    } else {
				player.newRound(null, null);
		    }
		}
		
		setHasOptionsMenu(true);
		setRetainInstance(true);
	}
	
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		
		mainView = inflater.inflate(R.layout.land_player_screen, container, false);
		
		TextView playerName = (TextView)mainView.findViewById(R.id.player_name);
		
		cardDisplay = (CardDisplayView)mainView.findViewById(R.id.player_cards);
		crystalDisplay = (CrystalDisplayView)mainView.findViewById(R.id.player_crystals);
		
		roundStatus = (TextView)mainView.findViewById(R.id.round_status);
		
		playTurnButton = (Button)mainView.findViewById(R.id.play_turn_button);
		playTurnButton.setOnClickListener(this);
		
		endRoundButton = (Button)mainView.findViewById(R.id.end_round_button);
		endRoundButton.setOnClickListener(this);
		
		playerLogScroll = (ScrollView)mainView.findViewById(R.id.player_log_scroll);
		playerLog = (TextView)mainView.findViewById(R.id.player_log);
		
		View crystalSection = mainView.findViewById(R.id.crystal_section);
		
		if (player.getName().equals(MKCharacter.VOLKARE.getName())) {
			crystalSection.setVisibility(View.GONE);
			roundStatus.setVisibility(View.INVISIBLE);
			showWounds = true;
		}

		setBackgroundImage(MKCharacter.findByName(player.getName()));
		playerName.setText(player.getName());
		
		this.onLogChanged("");
		
		return mainView;
	}
	
	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		
		outState.putSerializable(DUMMY_PLAYER_KEY, this.player);
		outState.putCharSequence(GAME_LOG, playerLog.getText());
	}
	
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		DummyPlayer player = null;
		
		if (savedInstanceState != null) {
			player = (DummyPlayer)savedInstanceState.getSerializable(DUMMY_PLAYER_KEY);
		} 
		
		if (player != null) {
			Log.d("restore", player.getName());
			if (player.getName().equals(MKCharacter.VOLKARE.getName())) {
				mainView.findViewById(R.id.crystal_section).setVisibility(View.GONE);
				roundStatus.setVisibility(View.INVISIBLE);
				showWounds = true;
			}
			this.player = player;
			
			CharSequence log = (savedInstanceState != null) ? savedInstanceState.getCharSequence(GAME_LOG) : player.getLog();
			if (log != null) {
				playerLog.setText(log, BufferType.SPANNABLE);
			}
		}
		
		setSaveStateOnDestroy(true);
		
		if (this.player != null) {
			((MKDummyPlayerActivity)getActivity()).setPlayerTabName(this.player.getName());
		}
	}
	
	@Override
	public void onPause() {
		super.onPause();
		player.removeAllPlayerListeners();
	}
	
	@Override
	public void onResume() {
		super.onResume();
		player.addPlayerListener(this);
		refreshCardAndCrystalViews();
		player.refreshListeners();
	}
	
	@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    	inflater.inflate(R.menu.player_menu, menu);
    	super.onCreateOptionsMenu(menu, inflater);
    	this.onLogChanged("");
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    	Intent i;
    	switch(item.getItemId()) {
    		case R.id.menu_help_option:
    			i = new Intent(getActivity(), HelpActivity.class);
    			startActivity(i);
    			break;
    		case R.id.menu_about_option:
    			AlertDialog about = new AlertDialog.Builder(getActivity())
					.setTitle(R.string.about_title)
					.setMessage(Html.fromHtml(getString(R.string.about_content)))
					.create();
			
    			about.show();
    			break;
    		case R.id.menu_save_option:
    			saveGameToFile();
    			break;
    		case R.id.menu_settings_option:
    			i = new Intent(getActivity(), PlayerPreferences.class);
    			startActivity(i);
    			break;
    		default:
    			break;
    	}
    	
    	return true;
    }
	
	
	@Override
	public void onClick(View v) {
		if (v.equals(playTurnButton)) {
			playTurnButton.setClickable(false);
			playTurnButton.setEnabled(false);
			player.takeTurn();
			Handler handler = new Handler();
			handler.postDelayed(new Runnable() {
				public void run() {
					Log.d("onClick", "End of round? " + endOfRound);
					playTurnButton.setEnabled(!endOfRound);
					playTurnButton.setClickable(!endOfRound);
				}
			}, 500);
		} else if (v.equals(endRoundButton)) {
			if (player.getName().equals(MKCharacter.VOLKARE.getName())) {
				player.newRound(null, null);
			} else {
				getActivity().showDialog(NEW_ROUND_DIALOG);
			}
		}
	}
	
	@Override
	public void onStop() {
		if (saveStateOnDestroy) {
			saveGameToFile();
		}
		super.onStop();
	}

	@Override
	public void onRoundEndStatusChange(boolean status) {
		endOfRound = status;
		if (status) {
			roundStatus.setText(R.string.end_round_declared);
			playTurnButton.setClickable(false);
			playTurnButton.setEnabled(false);
		} else {
			roundStatus.setText(R.string.end_round_not_declared);
			playTurnButton.setClickable(true);
			playTurnButton.setEnabled(true);
		}
	}

	@Override
	public void onCrystalsChanged(Map<ManaColor, Integer> crystals) {
		// DO NOTHING, HANDLED BY CRYSTAL VIEW
	}

	@Override
	public void onDeckChanged(CardDeck deck) {
		// DO NOTHING, HANDLED BY CARD VIEW
	}

	@Override
	public void onLogChanged(CharSequence newMessage) {
		if (playerLog == null || player == null) return;
		playerLog.setText(StringUtils.formatMessage(player.getLog()));
		playerLogScroll.postDelayed(new Runnable() {
			@Override
			public void run() {
				playerLogScroll.scrollTo(0, playerLog.getBottom());
			}
		}, 50);
	}
	
	@Override
	public void onDismiss(DialogInterface dialog) {
		if (dialog instanceof NewRoundDialog) {
			ManaColor newCard = ((NewRoundDialog) dialog).getNewCardColor();
			ManaColor newCrystal = ((NewRoundDialog) dialog).getNewCrystalColor();
			Set<Integer> tactics = ((NewRoundDialog) dialog).getAvailableTactics();
			
			Integer tactic = player.newRound(newCard, newCrystal, tactics);
			if (tactic != null) {
				((NewRoundDialog)dialog).selectTactic(tactic);
			}
		}
	}
	
	@Override
	public void onTabUnselected() {
		setSaveStateOnDestroy(false);
	}
	
	public void setSaveStateOnDestroy(boolean saveStateOnDestroy) {
		this.saveStateOnDestroy = saveStateOnDestroy;
	}
	
	public DummyPlayer getPlayer() {
		return player;
	}
	
	private void setBackgroundImage(MKCharacter character) {
		ImageView imgView = (ImageView)mainView.findViewById(R.id.player_screen_background);
		BitmapDrawable factionImage = (BitmapDrawable)getResources().getDrawable(character.getFactionImageResourceId());
		factionImage.setAlpha(0x22);
		imgView.setImageDrawable(factionImage);
	}
	
	private void saveGameToFile() {
		try {
			FileOutputStream fos = getActivity().openFileOutput(getString(R.string.save_file), Context.MODE_PRIVATE);
			ObjectOutputStream os = new ObjectOutputStream(fos);
			os.writeObject(player);
			os.close();
			
			Toast.makeText(getActivity(), R.string.game_saved, Toast.LENGTH_SHORT).show();
		} catch (IOException ioe) {
			
		}
	}
	
	private void restoreGameFromFile() {
		try {
			FileInputStream fis = getActivity().openFileInput(getString(R.string.save_file));
			ObjectInputStream is = new ObjectInputStream(fis);
		
			DummyPlayer savedPlayer = (DummyPlayer)is.readObject();
			this.player = savedPlayer;
			
			is.close();
		} catch (IOException ioe) {
			Toast.makeText(getActivity(), "Could not open save file (missing or corrupt).", Toast.LENGTH_SHORT).show();
			getActivity().finish();
		} catch (ClassNotFoundException cnfe) {
			throw new RuntimeException(cnfe);
		}
	}
	
	private void refreshCardAndCrystalViews() {
		ViewGroup parent = (ViewGroup)cardDisplay.getParent();
		int oldIndex = parent.indexOfChild(cardDisplay);
		Context c = parent.getContext();
		CardDisplayView newCardView = CardDisplayViewFactory.createCardDisplayView(PreferenceManager.getDefaultSharedPreferences(c), c);
		newCardView.showWounds(showWounds);
		parent.removeView(cardDisplay);
		parent.addView(newCardView, oldIndex);
		cardDisplay = newCardView;
		player.addPlayerListener(newCardView);		
		
		parent = (ViewGroup)crystalDisplay.getParent();
		oldIndex = parent.indexOfChild(crystalDisplay);
		c = parent.getContext();
		CrystalDisplayView newCrystalView = CrystalDisplayViewFactory.createCrystalDisplayView(PreferenceManager.getDefaultSharedPreferences(c), c);
		parent.removeView(crystalDisplay);
		parent.addView(newCrystalView, oldIndex);
		crystalDisplay = newCrystalView;
		player.addPlayerListener(newCrystalView);
		
		player.setTimestampDisplay(PreferenceManager.getDefaultSharedPreferences(c).getBoolean("show_timestamp", false));
	}

}
